#ifndef _BARTER_SERVER_NETWORKMESSAGE_H_
#define _BARTER_SERVER_NETWORKMESSAGE_H_

#include <string>
#include <string.h>

struct Header_t
{
	unsigned short DataSize; // encrypted size
	unsigned short RealSize; // un-encrypted size
};

class NetworkMessage
{
private:
	static const int MaxSize = 32786;
	static const int HeaderSize = 4;
	unsigned int Position, Length;
	unsigned char Buffer[MaxSize];
	bool CanAdd(int size)
	{
		return (Length + size <= MaxSize - HeaderSize);
	}
public:
	NetworkMessage()
	{
		Reset();
	}
	NetworkMessage(const NetworkMessage& other)
	{
		Copy(other);
	}
	NetworkMessage& operator=(const NetworkMessage& other)
	{
		Copy(other);
		return *this;
	}
	void Reset()
	{
		Position = HeaderSize; // always leave enough room for the header
		Length = 0;
	}
	void AddByte(unsigned char d);
	void Add2Bytes(unsigned short d)
	{
		if (!CanAdd(2))
		{
			return;
		}
		AddByte((d >> 8) & 0xFF);
		AddByte(d & 0xFF);
	}
	void Add4Bytes(unsigned long d)
	{
		if (!CanAdd(4))
		{
			return;
		}
		Add2Bytes((d >> 16) & 0xFFFF);
		Add2Bytes(d & 0xFFFF);
	}
	void Add8Bytes(unsigned long long d)
	{
		if (!CanAdd(8))
		{
			return;
		}
		Add4Bytes((d >> 32) & 0xFFFFFFFF);
		Add4Bytes(d & 0xFFFFFFFF);
	}
	void AddRaw(const char*, int);
	void AddString(std::string);
	unsigned char GetByte();
	unsigned short Get2Bytes()
	{
		return (GetByte() << 8) | GetByte(); // BigEndian byte order
	}
	unsigned long Get4Bytes()
	{
		return (Get2Bytes() << 16) | Get2Bytes();
	}
	unsigned long long Get8Bytes()
	{
		return (((unsigned long long)Get4Bytes()) << 32) | ((unsigned long long)Get4Bytes());
	}
	void GetRaw(char*, int);
	std::string GetString();
	void Append(NetworkMessage& other) // append the data section
	{
		if (this == &other) // some smart ass is trying to append `this'
		{
			return;
		}
		if (CanAdd(other.Length))
		{
			for (unsigned int i = HeaderSize; i < other.Length; i++)
			{
				AddByte(other.GetByte());
			}
		}
	}
	int GetPosition() // excludes the header
	{
		return Position - HeaderSize;
	}
	void SetPosition(int pos) // pos does not include the header
	{
		Position = pos + HeaderSize;
	}
	int GetLength()
	{
		return Length;
	}
	char* GetBuffer()
	{
		return (char*)Buffer;
	}
	char* GetBodyBuffer()
	{
		return (char*)(Buffer + HeaderSize);
	}
	void Copy(const NetworkMessage& other) // copy the whole message
	{
		if (this == &other) // some smart ass is trying to copy `this'
		{
			return;
		}
		Reset();
		Length = other.Length;
		memcpy(Buffer, other.Buffer, MaxSize);
	}
};

#endif // _BARTER_SERVER_NETWORKMESSAGE_H_
